package main

import (
	"fmt"
	"time"
)

// #1 使用闭包
func chanDemo() {
	//var c chan int // c == nil
	c := make(chan int)
	go func() {
		for {
			n := <-c
			fmt.Println(n)
		}
	}()
	c <- 1
	c <- 2
	time.Sleep(time.Millisecond) // 防止main函数直接退出
}

// #2 channel作为参数
func worker(id int, c chan int) {
	for {
		fmt.Printf("Worker %d received %d\n", id, <-c)
	}
}

func chanDemo2() {
	c := make(chan int)
	go worker(0, c)
	c <- 1
	c <- 2
	time.Sleep(time.Millisecond)
}

// #3
func worker3(id int, c chan int) {
	for {
		fmt.Printf("Worker %d received %c\n", id, <-c)
	}
}

func chanDemo3() {
	var channels [10]chan int
	for i := 0; i < 10; i++ {
		channels[i] = make(chan int)
		go worker3(i, channels[i])
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'a' + i
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'A' + i
	}

	time.Sleep(time.Millisecond)
}

// #4 channel作为返回值
//func createWorker(id int) chan int {
func createWorker(id int) chan<- int { // 返回值channel，外面使用是用来发数据的（chan<- int），如果是接收数据（<-chan int）
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d received %c\n", id, <-c)
		}
	}()
	return c
}

func chanDemo4() {
	//var channels [10]chan int
	var channels [10]chan<- int
	for i := 0; i < 10; i++ {
		channels[i] = createWorker(i)
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'a' + i
	}

	for i := 0; i < 10; i++ {
		channels[i] <- 'A' + i
	}

	time.Sleep(time.Millisecond)
}

// #5
func bufferedChannel() {
	c := make(chan int)

	c <- 1 // 只发送数据，没人接收会挂死，fatal error: all goroutines are asleep - deadlock!
}

// #6
func worker6(id int, c chan int) {
	for {
		fmt.Printf("Worker %d received %d\n", id, <-c) // channel close后，还是会读到数据，但是为0
	}
}

func createWorker6(id int) chan<- int {
	c := make(chan int)
	go worker6(id, c)
	return c
}

func bufferedChannel6() {
	c := make(chan int, 3)
	go worker6(0, c)
	c <- 1
	c <- 2
	c <- 3
	c <- 4
	time.Sleep(time.Millisecond)
}

// #7
func worker7(id int, c chan int) {
	for {
		n, ok := <-c // channel close后，还是会读到数据，但是为0
		if !ok {
			break
		}
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

func worker8(id int, c chan int) {
	for n := range c {
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

func channelClose() {
	c := make(chan int)
	//go worker7(0, c)
	go worker8(0, c)
	c <- 1
	c <- 2
	c <- 3
	c <- 4
	close(c) // close后还是能读到数据
	time.Sleep(time.Millisecond)
}

func main() {
	fmt.Println("Channel as first-class citizen")
	//chanDemo()
	//chanDemo2()
	//chanDemo3()
	//chanDemo4()
	fmt.Println("Buffered channel")
	//bufferedChannel()
	//bufferedChannel6()
	fmt.Println("Channel close and range")
	channelClose()
}
